<style scoped lang="less" rel="stylesheet/less">
    @borderColor :  #D8D8D8;
    .ruicar-afs-upload {
        .uploader-drop {
            padding: 0;
        }

        .ruicar-afs-upd-btn {
            width: 100%;
            padding: 20px 20px 18px;
            position: relative;
            border: none;
        }

        .upload-list{
            padding-top: 5px;
            padding-bottom: 5px;
        }
        .border-top {
            width: 100%;
            height: 1px;
            position: absolute;
            left: 0;
            top: 0;
            background-image: linear-gradient(to right, @borderColor 0%, @borderColor 50%, transparent 50%);
            background-size: 11px 1px;
            background-repeat: repeat-x;
        }

        .border-left {
            width: 1px;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
            background-image: linear-gradient(to top, @borderColor 0%, @borderColor 50%, transparent 50%);
            background-size: 1px 11px;
            background-repeat: repeat-y;
        }

        .border-bottom {
            width: 100%;
            height: 1px;
            position: absolute;
            left: 0;
            bottom: 0;
            background-image: linear-gradient(to right, @borderColor 0%, @borderColor 50%, transparent 50%);
            background-size: 11px 1px;
            background-repeat: repeat-x;
        }

        .border-right {
            width: 1px;
            height: 100%;
            right: 0;
            top: 0;
            background-image: linear-gradient(to top, @borderColor 0%, @borderColor 50%, transparent 50%);
            background-size: 1px 11px;
            background-repeat: repeat-y;
            position: absolute;
        }
        .uploadTitle {
            display: inline-block;
            height: 24px;
            line-height: 24px;
            padding: 0 7px;
            font-size: 12px;
            border-radius: 3px;
            color: #fff;
            background-color: #EB9620;
            border-color: #EB9620;
        }
    }
</style>
<template>
    <uploader
            ref="uploader"
            :options="options"
            :autoStart="false"
            @file-added="onFileAdded"
            @file-success="onFileSuccess"
            @file-progress="onFileProgress"
            @file-error="onFileError"
            class="uploader-app">
            <uploader-unsupport></uploader-unsupport>

            <uploader-drop>
                <uploader-btn :attrs="attrs" class="ruicar-afs-upd-btn" ref="uploadButton">
                    <div class="border-top"></div>
                    <div class="border-left"></div>
                    <div class="border-bottom"></div>
                    <div class="border-right"></div>
                    <div class="button-wrapper"></div>
                    <div style="text-align: center">
<!--                        <Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>-->
                        <span class="uploadTitle">上传文件</span>
                        <p style="padding-top: 15px;">也可直接拖拽文件到此区域，完成上传</p>
                    </div>
                </uploader-btn>
            </uploader-drop>
            <div class="upload-list">
                <Table border :columns="fileColumns" :data="fileList" no-data-text="暂无待上传文件" :max-height="tableMaxHeight">
                    <template slot-scope="{ row }" slot="size">
                        {{(row.size/1024/1024).toFixed(2)}}MB
                    </template>
                    <template slot-scope="{ row }" slot="speed">
                        <span v-if="row.currentSpeed/1024/1024>1">
                            {{(row.currentSpeed/1024/1024).toFixed(2)}}MB/s
                        </span>
                        <span v-else>
                            {{(row.currentSpeed/1024).toFixed(2)}}KB/s
                        </span>
                    </template>

                    <template slot-scope="{ row }" slot="status">
                        <strong v-if="row.processStatus=='md5'">
                            校验MD5 {{row.md5Percent}}%
                        </strong>
                        <strong v-if="row.processStatus=='queue'">
                            队列中
                        </strong>
                        <strong v-if="row.processStatus=='wait'">
                            等待上传
                        </strong>
                        <div v-if="row.processStatus=='uploading'||row.processStatus=='pause'">
                            <Progress :percent="row.percent" status="active" :stroke-width="10" />
                        </div>
                        <div v-if="row.processStatus=='md5_error'">
                            文件md5校验失败,请检查文件
                        </div>
                        <div v-if="row.processStatus=='error'">
                            文件上传失败
                        </div>
                        <div v-if="row.processStatus=='process'">
                            服务器处理中
                        </div>
                        <div v-if="row.processStatus=='finish'">
                            处理完成
                        </div>
                        <div v-if="row.processStatus=='illegal'">
                            文件不合法
                        </div>
                        <div v-if="row.processStatus=='oversize'">
                            文件过大
                        </div>
                        <div v-if="row.processStatus=='success'">
                            <Progress :percent="row.percent" status="active" :stroke-width="10" />
                        </div>
                    </template>

                    <template slot-scope="{ row ,index}" slot="opts">
                        <span v-if="row.processStatus=='error'">
                            <Button type="primary"  icon="ios-refresh" @click="retryUpload(row.uniqueIdentifier)">重试</Button>
                            &nbsp;&nbsp;
                        </span>
                        <span v-if="row.processStatus=='pause'">
                            <Button type="primary"  icon="ios-play" @click="resumeUpload(row.uniqueIdentifier)">继续</Button>
                            &nbsp;&nbsp;
                        </span>
                        <span v-if="row.processStatus=='uploading'">
                            <Button type="primary"  icon="ios-pause" @click="pauseUpload(row.uniqueIdentifier)">暂停</Button>
                            &nbsp;&nbsp;
                        </span>
                        <span v-if="row.processStatus=='success'||row.processStatus=='finish'
                                    ||row.processStatus=='pause'||row.processStatus=='wait'
                                    ||row.processStatus=='uploading'||row.processStatus=='error'
                                    ||row.processStatus=='illegal'||row.processStatus=='oversize'">
                            <Button type="error"  icon="md-close" @click="cancelFile(row.uniqueIdentifier,row.md5,index)">取消</Button>
                        </span>
                    </template>
                </Table>
            </div>
        </uploader>
</template>

<script>
    import {ACCEPT_CONFIG,FILE_SIZE_CONFIG,UPLOAD_URIS} from './config/config'
    import SparkMD5 from 'spark-md5'
    import {merge,deleteFile} from '@/projects/basic/api/file-center/index'
    export default{
        name: 'fileUpload-com',
        props: {
            query:{
                type:Object,
                required:false
            },
            requestPath:{
                type:String,
                required:false,
                default: ''
            },
            tableMaxHeight:{
                type:[String,Number],
                required:false,
                default: 0
            },
            chunkEnable:{
                type:Boolean,
                required:false,
                default:true
            },
            fileSelected:{
                type:Function,
                default:(guid)=>{
                    return ()=>{return {}}
                }
            }
        },
        data() {
            return {
                fileColumns: [
                    {
                        title: '文件名',
                        key: 'name',
                        width: 130,
                        tooltip:true
                    },
                    {
                        title: '大小',
                        key: 'size',
                        width:100,
                        slot:'size',
                        tooltip:true
                    },
                    {
                        title: '进度',
                        slot:'status'
                    },
                    {
                        title: '速率',
                        width:100,
                        slot:'speed'
                    },
                    {
                        title: '剩余',
                        width:80,
                        key:'remainTime'
                    },
                    {
                        title: '操作',
                        width:180,
                        slot:'opts'
                    }
                ],
                fileList:[],
                attrs: {
                    accept: ACCEPT_CONFIG.getAll()
                }
            }
        },
        mounted() {
        },
        computed: {
            uploader() {
                return this.$refs.uploader.uploader;
            },
            options(){
                return {
                    target: this.requestPath === ''?UPLOAD_URIS.chunkedUri:this.requestPath,
                    chunkSize:this.chunkEnable?FILE_SIZE_CONFIG.chunkedSize:FILE_SIZE_CONFIG.maxFileSize,
                    fileParameterName: 'file',
                    maxChunkRetries: this.chunkEnable?3:1,
                    simultaneousUploads: this.chunkEnable?3:1,
                    testChunks: true,
                    chunkEnable: this.chunkEnable,
                    progressCallbacksInterval:100,
                    checkChunkUploadedByResponse: function (chunk, message) {
                        if(!chunk.uploader.opts.chunkEnable){
                            return false;
                        }
                        let objMessage = JSON.parse(message);
                        if (objMessage.code==='0000'&&objMessage.data.finished===true) {
                            return true;
                        }else if(objMessage.code==='illegal'){
                            throw new Error(message);
                        }else if(objMessage.code==='oversize'){
                            throw new Error(message);
                        }
                        return (objMessage.data.uploadChunkNums || []).indexOf(chunk.offset + 1) >= 0
                    },
                    headers: {
                        'access-token': this.$store.getters.access_token,
                        'tenant-id': this.$store.getters.tenantId
                    },
                    query() {}
                }
            }
        },
        methods: {
            onFileAdded(file) {
                file.processStatus = 'queue';
                if(this.fileSelected) {
                    file._afsParams = this.fileSelected(file.guid);
                }else{
                    file._afsParams = {};
                }
                file.md5Percent = 0;
                let fileStatus = {
                    processStatus:'queue',
                    md5Percent:0,
                    percent:0,
                    currentSpeed:0,
                    remainTime:'-',
                    id:file.id,
                    name:file.name,
                    size:file.size,
                    uniqueIdentifier:file.uniqueIdentifier,
                    md5:'',
                    guid:file.guid,
                    signature:file.signature,
                    _afsParams:file._afsParams
                }
                this.fileList.push(fileStatus);
                this.computeMD5(file,fileStatus);
            },
            onFileProgress(rootFile, file, chunk) {
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        fileItem.currentSpeed = file.currentSpeed;
                        fileItem.processStatus='uploading';
                        fileItem.percent = Number.parseFloat((file.progress()*100).toFixed(2));
                        let remainTime = file.timeRemaining();
                        fileItem.remainTime = ((remainTime===Number.POSITIVE_INFINITY)?'-':remainTime)+'秒';
                    }
                })
            },
            onFileSuccess(rootFile, file, response, chunk) {
                let _res = JSON.parse(response);
                let self = this;
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        fileItem.processStatus='success';
                        fileItem.percent = Number.parseFloat((file.progress()*100).toFixed(2));
                        fileItem.remainTime = '0秒';
                        fileItem.processStatus='process';
                        if(!self.chunkEnable){
                            if(_res.code !== "0000"){
                                fileItem.processStatus = 'error';
                                this.$emit('uploadError', _res.data,fileItem.guid,fileItem._afsParams);
                            }else{
                                fileItem.processStatus = 'finish';
                                this.$emit('uploadSuccess', _res.data,fileItem.guid,fileItem._afsParams);
                                fileItem.uploadInfo = _res.data;
                            }
                        }else {
                            merge(fileItem.md5, file.guid, file.signature, file.name).then(res => {
                                if (res.code === "0000") {
                                    fileItem.processStatus = 'finish';
                                    this.$emit('uploadSuccess', res.data,fileItem.guid,fileItem._afsParams);
                                    fileItem.uploadInfo = res.data;
                                } else {
                                    fileItem.processStatus = 'error';
                                }
                            }).catch(() => {
                                fileItem.processStatus = 'error';
                            });
                        }
                    }
                })
            },
            onFileError(rootFile, file, response, chunk) {
                console.log("文件上传失败")
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        if(!file.illegal){
                            fileItem.processStatus='error';
                        }else{
                            fileItem.processStatus=file.illegalCode;
                        }
                        this.$emit('uploadError', {},fileItem.guid,fileItem._afsParams);
                    }
                })
            },

            /**
             * 计算md5，实现断点续传及秒传
             * @param file
             */
            computeMD5(file,fileStatus) {
                let fileReader = new FileReader();
                let time = new Date().getTime();
                let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
                let currentChunk = 0;
                const chunkSize = 10 * 1024 * 1000;
                let chunks = Math.ceil(file.size / chunkSize);
                let spark = new SparkMD5.ArrayBuffer();

                file.pause();

                loadNext();

                fileReader.onload = ( e => {
                    const hexString='0123456789ABCDEF';
                    fileStatus.processStatus = 'md5';
                    spark.append(e.target.result);
                    if(currentChunk==0){
                        let signature = new Uint8Array(e.target.result,0,64);
                        let hexArr = [];
                        signature.forEach(num=>{
                            hexArr.push(hexString.charAt((num  >>> 4)&0x0F))// 高4位
                            hexArr.push(hexString.charAt(num&0x0F))// 低4位
                        })
                        file.signature = hexArr.join('');
                    }
                    if (currentChunk < chunks) {
                        currentChunk++;
                        loadNext();
                        fileStatus.md5Percent = ((currentChunk/chunks)*100).toFixed(0);
                    } else {
                        let md5 = spark.end();
                        this.computeMD5Success(md5, file,fileStatus);
                        console.log(`MD5计算完毕：${file.name} \nMD5：${md5} \n分片：${chunks} 大小:${file.size} 用时：${new Date().getTime() - time} ms`);
                        // file.resume()
                    }
                });

                fileReader.onerror = function () {
                    fileStatus.processStatus = 'md5_error';
                    this.$Message.error(`文件${file.name}读取出错，请检查该文件`);
                    file.cancel();
                };

                function loadNext() {
                    let start = currentChunk * chunkSize;
                    let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
                    fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
                }
            },

            computeMD5Success(md5, file,fileStatus) {
                // 将自定义参数直接加载uploader实例的opts上
                Object.assign(this.uploader.opts, {
                    query: {
                        ...this.params,
                    }
                })
                fileStatus.md5 = md5;
                fileStatus.processStatus = 'wait';
                file.md5 = md5;
                file.resume();
            },
            resumeUpload(identifier){
                let file = this.uploader.getFromUniqueIdentifier(identifier);
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        fileItem.processStatus='uploading';
                    }
                })
                file.resume();
            },
            retryUpload(identifier){
                let file = this.uploader.getFromUniqueIdentifier(identifier);
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        fileItem.processStatus='uploading';
                    }
                })
                file.retry();
            },
            pauseUpload(identifier){
                let file = this.uploader.getFromUniqueIdentifier(identifier);
                this.fileList.forEach(fileItem => {
                    if(fileItem.guid===file.guid){
                        fileItem.processStatus='pause';
                    }
                })
                file.pause();
            },
            // 父组件 取消一个或者多个文件
            cancelFiles(arr) {
                let promiseArr = []
                if (!arr) {
                    this.fileList.forEach((ele, index) => {
                        promiseArr.push(this.cancelSingleFile(ele.uniqueIdentifier, ele.md5, index))
                    })
                } else if (Array.isArray(arr)) {
                    arr.forEach(e => {
                        let index = this.fileList.findIndex(itm => itm.md5 === e)
                        if (index > -1) {
                            const {uniqueIdentifier, md5} = this.fileList[index]
                            promiseArr.push(this.cancelSingleFile(uniqueIdentifier, md5, index))
                        }
                    })
                }
                Promise.all(promiseArr).then((values) => {
                    console.log('cancelFiles',values);
                });
            },
            cancelSingleFile(identifier, md5, fileIndex) {
                this.uploader.removeFile(this.uploader.getFromUniqueIdentifier(identifier));
                let prom = null;
                let fileItem = this.fileList.splice(fileIndex, 1)[0];
                if (fileItem && fileItem.uploadInfo && this.chunkEnable) {
                    prom = deleteFile(fileItem.uploadInfo.key)
                }
                return prom;
            },
            cancelFile(identifier,md5,fileIndex){
               let fileItem = this.fileList.splice(fileIndex,1)[0];
                this.uploader.removeFile(this.uploader.getFromUniqueIdentifier(identifier));
                if(fileItem&&fileItem.uploadInfo){
                    this.$emit('deleteFile',fileItem.uploadInfo);
                    if(this.chunkEnable) {
                        deleteFile(fileItem.uploadInfo.key).then(res => {
                            if (res.code === "0000") {
                            }
                        });
                    }
                }
            }
        },
        watch: {},
        destroyed() {
        },
        components: {}
    }
</script>
